"""
断言工具模块
"""
import json
import jsonschema
import allure

class Assertions:
    """断言工具类，提供常用的API测试断言方法"""
    
    @staticmethod
    def assert_status_code(response, expected_status_code):
        """
        断言响应状态码
        
        Args:
            response: 响应对象
            expected_status_code: 期望的状态码
        """
        with allure.step(f"断言状态码为 {expected_status_code}"):
            actual_status_code = response.status_code
            assert actual_status_code == expected_status_code, \
                f"状态码断言失败，期望: {expected_status_code}，实际: {actual_status_code}"
    
    @staticmethod
    def assert_json_key(response, key):
        """
        断言JSON响应中包含指定的键
        
        Args:
            response: 响应对象
            key: 期望存在的键
        """
        with allure.step(f"断言响应包含键 '{key}'"):
            response_json = response.json()
            assert key in response_json, f"响应中未找到键 '{key}'"
    
    @staticmethod
    def assert_json_value(response, key, expected_value):
        """
        断言JSON响应中指定键的值
        
        Args:
            response: 响应对象
            key: 键
            expected_value: 期望的值
        """
        with allure.step(f"断言键 '{key}' 的值为 '{expected_value}'"):
            response_json = response.json()
            assert key in response_json, f"响应中未找到键 '{key}'"
            actual_value = response_json[key]
            assert actual_value == expected_value, \
                f"值断言失败，键: '{key}'，期望: '{expected_value}'，实际: '{actual_value}'"
    
    @staticmethod
    def assert_json_schema(response, schema):
        """
        断言JSON响应符合指定的JSON Schema
        
        Args:
            response: 响应对象
            schema: JSON Schema
        """
        with allure.step("断言响应符合JSON Schema"):
            response_json = response.json()
            try:
                jsonschema.validate(instance=response_json, schema=schema)
            except jsonschema.exceptions.ValidationError as e:
                allure.attach(
                    json.dumps(response_json, ensure_ascii=False, indent=2),
                    name="实际响应",
                    attachment_type=allure.attachment_type.JSON
                )
                allure.attach(
                    json.dumps(schema, ensure_ascii=False, indent=2),
                    name="期望Schema",
                    attachment_type=allure.attachment_type.JSON
                )
                raise AssertionError(f"JSON Schema验证失败: {str(e)}")
    
    @staticmethod
    def assert_response_time(response, max_time):
        """
        断言响应时间在指定范围内
        
        Args:
            response: 响应对象
            max_time: 最大响应时间（秒）
        """
        with allure.step(f"断言响应时间小于 {max_time} 秒"):
            response_time = response.elapsed.total_seconds()
            assert response_time < max_time, \
                f"响应时间断言失败，期望小于: {max_time}秒，实际: {response_time}秒"
    
    @staticmethod
    def assert_header_exists(response, header):
        """
        断言响应头中包含指定的头
        
        Args:
            response: 响应对象
            header: 期望存在的头
        """
        with allure.step(f"断言响应头包含 '{header}'"):
            assert header.lower() in {k.lower(): v for k, v in response.headers.items()}, \
                f"响应头中未找到 '{header}'"
    
    @staticmethod
    def assert_header_value(response, header, expected_value):
        """
        断言响应头中指定头的值
        
        Args:
            response: 响应对象
            header: 头
            expected_value: 期望的值
        """
        with allure.step(f"断言响应头 '{header}' 的值为 '{expected_value}'"):
            headers_lower = {k.lower(): v for k, v in response.headers.items()}
            assert header.lower() in headers_lower, f"响应头中未找到 '{header}'"
            actual_value = headers_lower[header.lower()]
            assert actual_value == expected_value, \
                f"响应头值断言失败，头: '{header}'，期望: '{expected_value}'，实际: '{actual_value}'" 